package com.ltv.xiangqibook.web;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStreamReader;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.StringTokenizer;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;

import org.w3c.dom.Document;
import org.w3c.dom.Element;

import com.ltv.xiangqibook.common.GameIDCreator;
import com.sun.org.apache.xml.internal.serialize.OutputFormat;
import com.sun.org.apache.xml.internal.serialize.XMLSerializer;

public class TreeGenerator {
    
    private static TreeGenerator instance;
    private StringBuffer tree;
    
    private TreeGenerator() {
    }
    
    public static TreeGenerator getInstance() {
        if (instance == null) {
            instance = new TreeGenerator();
        }
        
        return instance;
    }
    
    public synchronized void initTree(File path, String gameId) throws Exception {
        tree = new StringBuffer();
        tree.append("<ul id=\"browser\" class=\"filetree\">\n");
        createXML(path);
        
        BufferedReader fileReader = new BufferedReader(
                new InputStreamReader(new FileInputStream(System.getProperty("java.io.tmpdir") + "/xiangqibook-tree.xml")));
        String line = fileReader.readLine();
        line = fileReader.readLine();
        line = fileReader.readLine();
        
        List<String> lines = new ArrayList<String>();
        
        while (line != null) {
            lines.add(line);
            line = fileReader.readLine();
        }
        
        lines.remove(lines.get(lines.size() - 1));
        
        for (String l : lines) {
            tree.append(toHtmlLine(l, gameId) + "\n");
        }
        tree.append("</ul>\n");
    }
    
    private String toHtmlLine(String xmlLine, String gameId) throws Exception {
        String ret = "";
        if (xmlLine.trim().startsWith("<Folder") && xmlLine.trim().endsWith("\"/>")) {
        	String fullPath = getFullPath(xmlLine);
        	if (fullPath != null) {
        		xmlLine = xmlLine.replace(" fullpath=\"" + fullPath + "\"", "");
        	}
            ret = "";
            ret = xmlLine.replace("\"/>", "</span></li>");
            
            String liCssClass = "closed";
            
            if (gameId != null) {
            	List<String> gameIdList = getAllGameID(fullPath);
            	if (gameIdList.contains(gameId)) {
            		liCssClass = "opened";
            	}
            }
            ret = ret.replace("<Folder value=\"", "<li class=\"" + liCssClass + "\"><span class=\"folder\">");
            
            return ret;
        }
        
        if (xmlLine.trim().startsWith("<Folder") && xmlLine.trim().endsWith("\">")) {
        	String fullPath = getFullPath(xmlLine);
        	if (fullPath != null) {
        		xmlLine = xmlLine.replace(" fullpath=\"" + fullPath + "\"", "");
        	}
            ret = "";
            ret = xmlLine.replace("\">", "</span><ul>");
            String liCssClass = "closed";
            if (gameId != null) {
            	List<String> gameIdList = getAllGameID(fullPath);
            	if (gameIdList.contains(gameId)) {
            		liCssClass = "opened";
            	}
            }
            ret = ret.replace("<Folder value=\"", "<li class=\"" + liCssClass + "\"><span class=\"folder\">");
            
            return ret;
        }
        
        if (xmlLine.trim().equals("</Folder>")) {
            ret = "";
            ret = xmlLine.replace("</Folder>", "</ul></li>");
            
            return ret;
        }
        
        if (xmlLine.trim().startsWith("<File") && xmlLine.trim().endsWith("\"/>")) {
            ret = "";
            ret = xmlLine.replace("\"/>", "</a></span></li>");
            ret = ret.replace("<File game_id=\"", "<li><span class=\"file\"><a href=\"../XiangQiGame?game_id=");
            ret = ret.replace("value=\"", "target=\"game\">");
            
            return ret;
        }
        return ret;
    }

    public String getTree() {
    	if (tree != null) {
    		return tree.toString();
    	}
    	
    	return "";
    }
    
    public static void main(String[] args) {
        System.out.println(TreeGenerator.getInstance().getTree());
    }
    
    private void createXML(File path) throws Exception {

        // initiating document factory
        DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory
                .newInstance();
        DocumentBuilder documentBuilder = documentBuilderFactory
                .newDocumentBuilder();
        Document document = documentBuilder.newDocument();
        Element rootElement = document.createElement("Folder");
        document.appendChild(rootElement);

        rootElement.setAttribute("value", path.getName());

        // First call to explore the path
        listDirectories(rootElement, document, path);

        //print
        OutputFormat format = new OutputFormat(document);
        format.setIndenting(true);
        format.setLineWidth(Integer.MAX_VALUE);

        //to generate output to console use this serializer
        //XMLSerializer serializer = new XMLSerializer(System.out, format);

        //to generate a file output use fileoutputstream instead of system.out
        XMLSerializer serializer = new XMLSerializer(
                new FileOutputStream(new File(System.getProperty("java.io.tmpdir") + "/xiangqibook-tree.xml")), format);

        serializer.serialize(document);
    }
    
    private void listDirectories(Element rootElement, Document document,
            File dir) throws Exception {

        File[] child = dir.listFiles();
        Arrays.sort(child);
        for (File f : child) {
            if (f.isDirectory()) { // is it a directory?
            	if (f.getName().indexOf(".svn") == -1) {
                    Element childElement = document.createElement("Folder");
                    childElement.setAttribute("value", f.getName());
                    childElement.setAttribute("fullpath", f.getAbsolutePath());
    
                    // appending the found dir name to the root element
                    rootElement.appendChild(childElement);
    
                    // Recurssive call to the same method where we find any folder
                    // in parent folder
                    listDirectories(childElement, document, f.getAbsoluteFile());
            	}

            } else { // what else? it is a file and for a file there is
                // no recursive call obviously ;)
                if (f.getName().endsWith(".pgn")) {
                    Element childElement = document.createElement("File");
                    
                    String displayValue = "";
                    String fileName = f.getName();
                    int index = f.getName().indexOf('_');
                    int gameIndex = -1;
                    
                    if (index >= 0) {
                        try {
                            gameIndex = Integer.parseInt(fileName.substring(0, index));
                        } catch (Exception e) {
                            gameIndex = -1;
                        }
                    }
                    
                    if (gameIndex != -1) {
                        displayValue = fileName.substring(index + 1, fileName.length() - 4);
                    } else {
                        displayValue = fileName.substring(0, fileName.length() - 4);
                    }
                    
                    childElement.setAttribute("value", displayValue);
                    
                    String gameIdInMD5 = GameIDCreator.getGameID(f);
                    childElement.setAttribute("game_id", gameIdInMD5);
                    
                    // appending the found file name to the root element
                    rootElement.appendChild(childElement);
                }
            }
        }

    }
    
    private String getFullPath(String xmlLine) {
    	StringTokenizer st = new StringTokenizer(xmlLine, "=\"");
    	while(st.hasMoreTokens()) {
    		String key = st.nextToken();
    		String val = "";
    		if (st.hasMoreTokens()) {
    			val = st.nextToken();
    		}
    		if (key.indexOf("fullpath") != -1) {
    			return val;
    		}
    	}
    	
    	return null;
    }
    
    
    private List<String> getAllGameID(String path) throws Exception {
    	// connecting to database
        Connection con = null;  
        Statement stmt = null;
        ResultSet rs = null;
        
        List<String> ret = new ArrayList<String>();
        
    	try {
            con = ConnectionPool.getInstance().getConnection();
            stmt = con.createStatement();
            rs = stmt.executeQuery("SELECT * FROM directories where full_path='" + path + "'");
            
            if (rs.next()) {
            	String gameIds[] = rs.getObject(3).toString().split("\\|");
            	for (String gameId : gameIds) {
            		ret.add(gameId);
            	}
            }
    	} finally {
            if(rs != null) {
                rs.close();
                rs = null;
            }
            if(stmt != null) {
                stmt.close();
                stmt = null;
            }
            if(con != null) {
                ConnectionPool.getInstance().returnConnection(con);
            }
    	}
    	
    	return ret;
    }
}
